package piconode.tutorials;

import piconode.core.node.EchoStateNetwork;
import piconode.factory.EchoStateNetworkFactory;
import piconode.factory.objectivefunctions.ObjectiveFunction;
import piconode.toolbox.Display;
import piconode.visualpiconode.Visualizer;

public class Tutorial_7_EchoStateNetwork {

	// testing. note that the ESN factory source code contains a more complete
	// demo (with evaluation of recovery from perturbations)
	public static void main(String[] args) {

		Display.info("### ECHO STATE NETWORK : initialization and learning tutorial ###\n20070613, niko.\n\n");

		double startTime = System.currentTimeMillis();

		// * build and display ESN

		Display.warning("Note: an ESN does not contain a \"bias\" node by default. You may want to create an additional input which fires always 1.0 depending on your experimental setup.");

		int nbIn = 1; // 1
		int reservoirSize = 100; // [1:100]
		int nbOut = 1; // 1

		boolean outputTanhFn = true; // true: tanh, false: linear

		boolean inputOutputDirectConnections = false;
		boolean outputSelfRecurrentConnections = false;

		EchoStateNetwork network = EchoStateNetworkFactory.createESN(nbIn, reservoirSize, nbOut, 0.05, // connection
				// density
				// [1:0.05]
				0.88, // dampening (1.0: spectral radius) [1:0.88]
				true, // input to reservoir connections. ignore=false, but
				// piconode needs at least one (possibliy unused) input
				// unit.
				inputOutputDirectConnections, // connections btw inputs and
				// outputs ?
				outputSelfRecurrentConnections, // self connections btw output
				// and output?
				true, // connections btw outputs and reservoir?
				0.5, // input->reservoir weight range [fixed]
				0.5, // reservoir->output initial weight range [learning]
				0.5, // output->reservoir weight range [fixed]
				0.5, // output->output self cnx (fixed)
				0.01, // noise value added to output when going back to
				// reservoir [1:0.01]
				outputTanhFn, // output Activation Function (true: tanh,
				// false: linear)
				true // display info ("verbose" mode).
				);
		/*
		 * @param __nbIn desired number of inputs + 1 (bias neuron, to be
		 * manually set to 1.0) @param __reservoirSize number of hidden units
		 * @param __nbOut @param __connectionDensity (btw 0 and 1). gives
		 * probability to have 1 or -1 rather than 0 value @param
		 * __spectralRadiusNormalizationValue must be <1 to ensure contraction
		 * (e.g. 0.9). @param __inputConnections consider/ignore input to
		 * reservoir connections @param __inputOutputDirectConnections allow
		 * direct connections from input to output ? @param
		 * __outputSelfRecurrentConnections allow recurrent connections for each
		 * output to itself ? @param __backwardConnections allow backward
		 * connections from output to reservoir? @param __inputWeightRange range
		 * (centered at zero) of weight values from inputs to reservoir (e.g.
		 * 2.0 means weights are btw -1 and 1) @param __outputWeightRange range
		 * (centered at zero) of weight values from outputs to reservoir (e.g.
		 * 2.0 means weights are btw -1 and 1) @param __backwardWeightRange
		 * range (centered at zero) of weight values from outputs back to
		 * reservoir (if backward cnx allowed, otw any value is ok). @param
		 * __noiseValue added noise to output nodes towards reservoir @param
		 * __outputActivationFunction output Activation Function (true: tanh,
		 * false: linear) @param __verbose if true, display information
		 * regarding reservoir initialization @return
		 */

		System.out.println("\n");
		network.displayInformation();

		ObjectiveFunction fn = new Sin7ObjectiveFunction();

		// step 1 : standard experimental setup : (1) washing out internal
		// dynamics (2) sampling and learning (3) testing with teacher forcing
		// (4) real-world condition testing

		System.out.println("#initial washout");
		EchoStateNetworkFactory.run(network, fn, 0, 100, false, false, true); // initial
		// washout
		// - no
		// teacher
		// forcing,
		// no
		// verbose
		// mode
		System.out.println("#sampling and learning");
		EchoStateNetworkFactory.sampleAndLearn(network, fn, 100, 200, true); // sample
		// and
		// learn
		System.out.println("#running (1)");
		EchoStateNetworkFactory.run(network, fn, 300, 100, true, true, true); // 100
		// it.
		// -
		// teacher
		// forcing,
		// verbose
		// mode
		System.out.println("#running (2)");
		EchoStateNetworkFactory.run(network, fn, 400, 100, true, false, true); // 100
		// it.
		// -
		// without
		// teacher
		// forcing,
		// verbose
		// mode

		// * display network graphical representation

		int returnValue = Visualizer.showNetwork(network);

		System.out.println("\n# Terminated (" + ((System.currentTimeMillis() - startTime) / 1000) + "s elapsed).");

	}

}
